<?php
/**
 * База данных mysql
 * 
 * Класс для работы с базой mysql
 * @author Anton Zavidov
 * @package myLiveShop
 */

import('core.db');
/**
 * Класс для работы с базой mysql
 *
 */
class Mysql extends DB{
	/**
	 * Последний запрос
	 *
	 * @var string
	 */
	private static $last_query='';
	/**
	 * Текущая сессия
	 *
	 * @var mixed
	 */
	private static $session;
	/**
	 * Конструктор
	 *
	 */
	public function __construct(){
		parent::__construct(__CLASS__);
	}
	/**
	 * Поличение инстанса класса
	 *
	 * @return Mysql
	 */
	public static function getInstance() {
		if (self::$instance === null)
		return self::$instance = new self();
		else
		return self::$instance;
	}
	/**
	 * Конект к базе данных
	 *
	 */
	public function connect(){
		if(!self::$session=mysql_connect(Config::_('db_host'),Config::_('db_user'),Config::_('db_pass'))){
			new DBExeption('Не могу подсоединится к Mysql',self::$exit_on_error?E_ERROR:E_WARNING,__FILE__,__LINE__,array('host'=>Config::_('db_host'),'user'=>Config::_('db_user'),'pasw'=>Config::_('db_pass')));
			return false;
		}
		if(!mysql_select_db(Config::_('db_name'))){
			new DBExeption('Не могу выбрать базу '.Config::_('db_name'),E_ERROR,__FILE__,__LINE__);
			return false;
		}
		L('Удачный конект к базе '.Config::_('db_name'));
		$this->query("SET CHARACTER SET utf8");
		return true;
	}
	/**
	 * Закрываем конект к базе
	 *
	 */
	public function close(){
		if(self::$session){
			mysql_close(self::$session);
			L('Закрыли коннект к базе');
			return true;
		}
		return false;
	}
	/**
	 * Запрос к базе
	 *
	 * @param string $query строка запроса
	 * @return mixed результат запроса
	 */
	public function query($query){
		if(!$this->isConnect()){
			if(!$this->connect())return;
		}
		$t=microtime(true);
		$m=memory_get_usage();
		$result=mysql_query($query,self::$session) or new DBExeption('Ошибка в запросе к БД',E_ERROR,__FILE__,__LINE__,array('message'=>mysql_error(),'query'=>$query));
		self::$last_query=$query;
		if(checkLogConfig('mysql'))new Log($query,0,false,false,array(
			'time'=>number_format(microtime(true)-$t,4),
			'memory'=>memory_get_usage()-$m));
		return $result;
	}
	/**
	 * Последний ID
	 *
	 * @return int
	 */
	public function lastId(){
		return mysql_insert_id(self::$session);
	}
	/**
	 * конструктор запросов
	 *
	 * @param array $params массив настроек в котром обязательно должны быть поле table
	 * @return unknown
	 */
	public function buildQuery($params){
		if(!isset($params['table'])){
			new CoreExeption('Не найден параметр table, нет возможности нормально построить запрос',E_WARNING,__FILE__,__LINE__,array('params'=>$params));
			return null;
		}
		if(isset($params['fields'])){
			if(is_array($params['fields'])){
				foreach ($params['fields'] as &$item) {
					if(!is_string($item)){
    					if(DB::apostrof($item->_('table'))==$params['table']){
					       $item=$item->fieldName();
    					}else{
    					   $fieldname=$item->fieldName();
    					   $item=$fieldname.' AS '.DB::apostrof($item->_('table').'_'.$item->_('name'));
    					}
					}
				}
				$params['fields']=implode(', ',$params['fields']);
			}
		}else{
			$params['fields']='*';
		}
		$sql='SELECT '.$params['fields'].' FROM '.$params['table'].
		(isset($params['join']) && $params['join']?self::buildJoin($params['join']):'').
		(isset($params['where'])&& $params['where']?' WHERE '.$params['where']:'').
		(isset($params['group']) && $params['group']?' GROUP BY '.$params['group']:'').
		(isset($params['order']) && $params['order']?' ORDER BY '.$params['order']:'').
		(isset($params['limit']) && $params['limit']?' LIMIT '.$params['limit']:'');		
		return $sql;
	}
	/**
	 * Строим join подзапрос
	 *
	 * @param array $join_list список подзапростов
	 * @return string подзапрос
	 */
	private static function buildJoin($join_list){
		if(!is_array($join_list))return '';
		$join=array();
		foreach ($join_list as $item) {
		    if(is_string($item)){
		        $join[]=$item;
		        continue;
		    }
			if(!isset($item['table']) ||!isset($item['key']) ||!isset($item['join_field']) ||!isset($item['join_table'])){
				new CoreExeption('Нет возможности построить join подзапрос так как отсутствует параметр table или key или join_field или join_table',E_WARNING,__FILE__,__LINE__,array('params'=>$item));
				continue;
			}
			$string='';
			if(isset($item['method'])){
				$string.=strtoupper($item['method']).' ';
			}else{
				$string.='LEFT JOIN ';
			}
			$string.=DB::apostrof($item['table']).' ON '.DB::apostrof($item['table'].DOT.$item['key']).'='.DB::apostrof($item['join_table'].DOT.$item['join_field']);
			$join[]=$string;
		}
		return ' '.implode(' ',$join);
	}
	/**
	 * Вставка данных
	 *
	 * @param string $таблица
	 * @param array массив данных
	 * @param array настройки ignore
	 */
	public function insert($table,$datas,$params=false){
		$query='INSERT'.(isset($params['igrore'])?' IGNORE':'').' INTO `'.$table.'`';
		//тип масива простой или многомерный
		$simple=null;
		//заначения
		$ret=array();
		//ключи
		$keys=array();
		//проходимся по масиву
		foreach ($datas as $key=>$value) {
			//если простой
			if(is_string($key) && $simple!==false){
				$simple=true;
				$keys[]=$this->apostrof($key);
				$ret[]=$this->eraseData($value);
			//если многомерный
			}elseif(is_array($value) && $simple!==true){
				$rem=array();
				//проходимся по подмасиву
				foreach ($value as $k=>$v){
					if($simple===null){
						$keys[]=$this->apostrof($k);
					}
					$rem[]=$this->eraseData($v);
				}
				$ret[]='('.implode(',',$rem).')';
				$simple=false;
			}else{
				new DBExeption('Ошибка в insert данных',E_ERROR,__FILE__,__LINE__,array('table'=>$table,'datas'=>$datas,'params'=>$params));
				return false;
			}
		}
		//собираем запрос
		$query.='('.implode(',',$keys).') VALUES ';
		if($simple===true){
			$query.='('.implode(',',$ret).')';
		}else{
			$query.=implode(',',$ret);
		}
		return $this->query($query);
	}
	/**
	 * Изменение данных
	 *
	 * @param string $таблица
	 * @param array массив данных
	 * @param array строка where
	 */
	public function update($table, $data, $where=''){
		$ret=array();
		foreach ($data as $key=>$value) {
			$ret[]=$this->apostrof($key).'='.$this->eraseData($value);
		}
		return $this->query('UPDATE '.$this->apostrof($table).' SET '.implode(', ',$ret).($where?' WHERE '.$where:''));
	}
	/**
	 * Удаление данных
	 *
	 * @param string $таблица
	 * @param array строка where
	 */
	public function delete($table, $where){
		return $this->query('DELETE FROM '.$this->apostrof($table).' WHERE '.$where);
	}
	/**
	 * Возвращает true если база подконекчена
	 * 
	 * @return boolean
	 */
	public function isConnect(){
		return (bool) self::$session;
	} 
	/**
	 * Защитить данные
	 *
	 * @param string $value
	 */
	public function escaped($value){
		return mysql_escape_string($value);
	}
	/**
	 * Получить массив данных по запросу
	 *
	 * @param mixed $result либо строка запроса либо ресурс
	 * @param boolean $one_row возврашать только один ряд
	 * @param mixed $one_field возвратить только этот столбец
	 */
	public function getArray($result,$one_row=false,$one_field=false){
		//если возвращать только один столбец значит и только один ряд
		if($one_field)$one_row=true;
		if(is_string($result))$result=$this->query($result);
		if($one_row){
			if(!$one_field || !is_string($one_field))return mysql_fetch_assoc($result);
			$result=mysql_fetch_assoc($result);
			return $result[$one_field];
		}
		$return=array();
		while($str=mysql_fetch_assoc($result)){
			$return[]=$str;
		}
		return $return;
	}
}